package com.runvp.service.auth.service;

import com.alibaba.fastjson.JSONObject;
import com.runvp.common.config.WechatConfigure;
import com.runvp.common.core.redis.RedisCache;
import com.runvp.common.enums.*;
import com.runvp.common.model.auth.BizUserBO;
import com.runvp.common.model.auth.LoginUser;
import com.runvp.common.model.vo.auth.ConfirmVO;
import com.runvp.common.model.vo.auth.OpenIdVO;
import com.runvp.common.model.vo.auth.PhoneVO;
import com.runvp.common.util.ToolUtils;
import com.runvp.common.utils.http.HutoolHttpClient;
import com.runvp.common.utils.validtion.CheckException;
import com.runvp.service.biz.domain.BizCustomer;
import com.runvp.service.biz.service.IBizCustomerService;
import com.runvp.service.biz.service.IBizCustomerWalletService;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class WechatAuthService  {

    @Autowired
    private TokenService tokenService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private IBizCustomerService bizCustomerService;
    @Autowired
    private IBizCustomerWalletService bizCustomerWalletService;
    /**
     * 获取openId
     * @param code
     * @return OpenIdVO
     */
    public OpenIdVO login(String code){
        log.info("getToken code : {}",code);
        CheckException.strEmptyThrowException(code,"code为空");
        String result = getOpenId(code);
        log.info("getToken result : {}",result);
        OpenIdVO vo = JSONObject.parseObject(result,OpenIdVO.class);
        String openId = vo.getOpenId();
        CheckException.strEmptyThrowException(openId,ErrorCode.AUTH_FAILURE.getDesc());
        BizCustomer customer = getBizCustomerByOpenId(openId);
        if(null == customer){
            //注册用户
            customer = new BizCustomer();
            customer.setOpenId(openId);
            customer.setSource(DataSource.WECHAT.getCode());
            customer.setType(UserType.CUSTOMER.getCode());
            customer.setRealAuthStatus(YesOrNo.NO.getCode());
            customer.setPid(0L);
            customer.setStatus(EnableStatus.ENABLE.getCode());
            bizCustomerService.insertBizCustomer(customer);
            //创建钱包
            bizCustomerWalletService.customerWallet(customer.getId());
        }
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(customer.getId());
        BizUserBO userBO = new BizUserBO();
        BeanUtils.copyProperties(customer,userBO);
        loginUser.setUserBO(userBO);
        Map<String,Object> map = tokenService.createToken(loginUser);
        vo.setToken(ToolUtils.toStr(map.get("access_token")));
        return vo;
    }
    private BizCustomer getBizCustomerByOpenId(String openId){
        BizCustomer query = new BizCustomer();
        query.setOpenId(openId);
        List<BizCustomer> customers = bizCustomerService.selectBizCustomerList(query);
        if(CollectionUtils.isEmpty(customers)){
            return null;
        }
        return customers.get(0);
    }
    /**
     * 获取 openID
     * @param code
     * @return str
     */
    public static String getOpenId(String code){
        StringBuffer url = new StringBuffer(WechatConfigure.getWechatAuthUrl())
                .append("?appid=").append(WechatConfigure.getApp_id())
                .append("&secret=").append(WechatConfigure.getSecret())
                .append("&js_code=").append(code)
                .append("&grant_type=authorization_code");
        return HutoolHttpClient.get(url.toString());
    }
    /**
     *
     * @param request
     * @return str
     */
    public String getPhone(PhoneVO request) {
        JSONObject  jsonObject = getPhoneNumber(request.getSessionKey(),request.getEncryptedData(),request.getIv());
        log.info("手机号对象:{}",jsonObject);
        CheckException.emptyThrowException(jsonObject,"手机号获取失败");
        //把手机号更新到用户信息
        String phone = jsonObject.getString("phoneNumber");
        CheckException.strEmptyThrowException(phone,"手机号获取失败");
        //更新手机号
        return phone;
    }
    /**
     * 确认
     * @param request
     */
    @Transactional
    public void confirm(ConfirmVO request) {
        //校验是否已经确认过
        //执行新增
        log.info("新用户执行新增:{}");
    }

    /**
     * 解密手机号
     * @author kemi
     * @param session_key
     * @param encryptedData
     * @param iv
     * @return json
     */
    private JSONObject getPhoneNumber(String session_key, String encryptedData, String iv ){
        byte[] dataByte = Base64.decode(encryptedData);
        byte[] keyByte = Base64.decode(session_key);
        byte[] ivByte = Base64.decode(iv);
        try {
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
//            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, "UTF-8");
                return JSONObject.parseObject(result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  null;
    }


}
